package com.myk.game.gobangchess.ai.symmetric;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * 文件名: SymmetryChecker.java
 * 功能: 提供用于验证棋块对称性的函数。
 */
public class SymmetryChecker {

    /**
     * 函数名: isSymmetric
     * 函数功能: 检查一个棋块是否具有对称性（横向、纵向、主对角线或反对角线）。
     *         该函数会调用 BoundingBoxFinder.getBoundingBoxCorners 来获取棋块的最小包围矩形。
     *
     * @param block 输入参数, 代表一个棋块。
     *              格式: List<int[]>。
     *              这是一个坐标列表，其中每个元素 `int[]` 代表一个棋子的坐标 {row, col}。
     *              列表大小可变，取决于棋块大小。
     *
     * @return boolean, 如果棋块是以上述任何一种方式对称的，则返回 true；否则返回 false。
     */
    public static boolean isSymmetric(List<int[]> block) {
        // 1. 处理简单情况：大小为1或2的棋块总是对称的。
        if (block == null || block.size() <= 2) {
            return true;
        }

        // 2. 获取最小包围矩形
        int[][] bbox = BoundingBoxFinder.getBoundingBoxCorners(block);
        if (bbox == null) return true; // 空棋块也视为对称

        int minRow = bbox[0][0];
        int maxRow = bbox[2][0];
        int minCol = bbox[0][1];
        int maxCol = bbox[1][1];

        int height = maxRow - minRow;
        int width = maxCol - minCol;

        // 3. 处理线性情况：如果棋块在一条直线上，总是对称的。
        if (height == 0 || width == 0) {
            return true;
        }

        // 4. 为了高效查找，将所有点放入一个HashSet
        Set<String> points = new HashSet<>();
        for (int[] p : block) {
            points.add(p[0] + "," + p[1]);
        }

        // 5. 检查各种对称性
        // 检查横向对称
        if (checkHorizontalSymmetry(block, points, minRow, maxRow)) {
            return true;
        }
        // 检查纵向对称
        if (checkVerticalSymmetry(block, points, minCol, maxCol)) {
            return true;
        }

        // 只有当包围盒是正方形时，才需要检查对角线对称
        if (height == width) {
            // 检查主对角线对称 (y=x type)
            if (checkMainDiagonalSymmetry(block, points, minRow, minCol)) {
                return true;
            }
            // 检查反对角线对称 (y=-x type)
            if (checkAntiDiagonalSymmetry(block, points, minRow, maxRow, minCol, maxCol)) {
                return true;
            }
        }

        // 6. 如果所有对称性检查都失败，则返回 false
        return false;
    }

    private static boolean checkHorizontalSymmetry(List<int[]> block, Set<String> points, int minRow, int maxRow) {
        for (int[] p : block) {
            int reflectedRow = minRow + maxRow - p[0];
            if (!points.contains(reflectedRow + "," + p[1])) {
                return false;
            }
        }
        return true;
    }

    private static boolean checkVerticalSymmetry(List<int[]> block, Set<String> points, int minCol, int maxCol) {
        for (int[] p : block) {
            int reflectedCol = minCol + maxCol - p[1];
            if (!points.contains(p[0] + "," + reflectedCol)) {
                return false;
            }
        }
        return true;
    }

    private static boolean checkMainDiagonalSymmetry(List<int[]> block, Set<String> points, int minRow, int minCol) {
        for (int[] p : block) {
            int reflectedRow = minRow + (p[1] - minCol);
            int reflectedCol = minCol + (p[0] - minRow);
            if (!points.contains(reflectedRow + "," + reflectedCol)) {
                return false;
            }
        }
        return true;
    }

    private static boolean checkAntiDiagonalSymmetry(List<int[]> block, Set<String> points, int minRow, int maxRow, int minCol, int maxCol) {
        for (int[] p : block) {
            // 反射点 (r', c') 满足 r' = minRow + maxCol - c, c' = minCol + maxRow - r
            // 但由于是正方形, maxRow - minRow = maxCol - minCol, 所以 maxRow - r = (minRow + width) - r
            // c' = minCol + (minRow + width) - r
            // 这个公式更通用: r' = minRow+maxCol-c, c' = minCol+maxRow-r
            int reflectedRow = minRow + maxCol - p[1];
            int reflectedCol = minCol + maxRow - p[0];
            if (!points.contains(reflectedRow + "," + reflectedCol)) {
                return false;
            }
        }
        return true;
    }

    /**
     * main 函数用于调用和验证 isSymmetric 函数。
     */
    public static void main(String[] args) {
        // --- 测试用例 ---
        // 1. 横向对称 ("T"形)
        List<int[]> horizontalBlock = new ArrayList<>(Arrays.asList(
                new int[]{2, 3}, new int[]{2, 4}, new int[]{2, 5}, new int[]{3, 4}, new int[]{4, 4}
        ));
        // 2. 纵向对称 ("H"形)
        List<int[]> verticalBlock = new ArrayList<>(Arrays.asList(
                new int[]{2, 2}, new int[]{3, 2}, new int[]{4, 2}, new int[]{3, 3}, new int[]{2, 4}, new int[]{3, 4}, new int[]{4, 4}
        ));
        // 3. 主对角线对称 ("\"形)
        List<int[]> mainDiagonalBlock = new ArrayList<>(Arrays.asList(
                new int[]{2, 2}, new int[]{3, 3}, new int[]{4, 4}, new int[]{2, 3}, new int[]{3, 2}
        ));
        // 4. 反对角线对称 ("/"形)
        List<int[]> antiDiagonalBlock = new ArrayList<>(Arrays.asList(
                new int[]{2, 4}, new int[]{3, 3}, new int[]{4, 2}, new int[]{2, 3}, new int[]{3, 4}
        ));
        // 5. 不对称 ("L"形)
        List<int[]> asymmetricBlock = new ArrayList<>(Arrays.asList(
                new int[]{5, 5}, new int[]{6, 5}, new int[]{7, 5}, new int[]{7, 6}, new int[]{7, 7}
        ));
        // 6. 线性棋块 (一行)
        List<int[]> linearBlock = new ArrayList<>(Arrays.asList(
                new int[]{1, 1}, new int[]{2, 1}, new int[]{3, 1}
        ));
        // 7. 小棋块 (大小为2)
        List<int[]> smallBlock = new ArrayList<>(Arrays.asList(
                new int[]{1, 1}, new int[]{1, 2}
        ));
        // 8. 自定义
        List<int[]> Block0 = new ArrayList<>(Arrays.asList(
                new int[]{1, 1}, new int[]{2, 1}, new int[]{2, 4}, new int[]{1, 2}, new int[]{1, 3}
        ));
        System.out.println("--- 验证 isSymmetric 函数 ---");
        System.out.println("横向对称块 ('T'形): " + isSymmetric(horizontalBlock));
        System.out.println("纵向对称块 ('H'形): " + isSymmetric(verticalBlock));
        System.out.println("主对角线对称块 ('\\'形): " + isSymmetric(mainDiagonalBlock));
        System.out.println("反对角线对称块 ('/'形): " + isSymmetric(antiDiagonalBlock));
        System.out.println("不对称块 ('L'形): " + isSymmetric(asymmetricBlock));
        System.out.println("线性块 (一行): " + isSymmetric(linearBlock));
        System.out.println("小棋块 (大小为2): " + isSymmetric(smallBlock));
        System.out.println("自定义: " + isSymmetric(Block0));
    }
}